package com.apes.scm.voucher.model;

import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.BaseModel;
import com.apes.framework.jpa.DefaultPersistListener;
import com.apes.framework.jpa.comment.Comment;
import com.apes.framework.jpa.generator.ApesGenerator;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.util.ApesConst;
import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.account.model.InventoryConsign;
import com.apes.scm.account.tax.model.Tax;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.product.model.ProductUom;
import com.apes.scm.masterdata.product.service.UomService;
import com.apes.scm.voucher.repository.VoucherItemRepository;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.SelectBeforeUpdate;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 功能：凭证明细
 *
 * @author xul
 * @create 2018-02-11 10:09
 */
@Getter
@Setter
@SelectBeforeUpdate
@DynamicInsert
@DynamicUpdate
@Entity
@EntityListeners(DefaultPersistListener.class)
@Table(name = VoucherItem.CONST_TABLE_NAME)
public class VoucherItem extends BaseModel {
    public static final String CONST_TABLE_NAME = "acc_voucher_item";

    @Id
    @Column(name = "id")
    @ApesGenerator(code = CONST_TABLE_NAME, name = "凭证明细")
    @Comment("凭证明细单号")
    private long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "owner_id", referencedColumnName = "id")
    @Comment("物权公司")
    private PartyRole owner; //物权公司

    public PartyRole obtainOwner() {
        return getOwner() != null ? getOwner() : voucher != null ? voucher.getCompany() : null;
    }

    @NotNull
    @ManyToOne(optional = false)
    @JoinColumn(name = "voucher_id", referencedColumnName = "id")
    @Comment("凭证单号")
    private Voucher voucher;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "supplier_id", referencedColumnName = "id")
    @Comment("供应商编码")
    private PartyRole supplier;

    @Column(name = "origin_item_id", length = 30)
    @Comment("源单据明细单号")
    private String originItemId;

    @Column(name = "source_item_id", length = 30)
    @Comment("来源单明细单号")
    private String sourceItemId;

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "product_id", referencedColumnName = "id")
    @Comment("商品编码")
    private Product product;

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "product_uom_id", referencedColumnName = "id")
    @Comment("计量单位编码")
    private ProductUom uom;

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "tax_id", referencedColumnName = "id")
    @Comment("税率编码")
    private Tax tax; //

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "inventory_batch_id", referencedColumnName = "id")
    @Comment("商品价值库存内码")
    private InventoryBatch inventoryBatch;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "inventory_consign_id", referencedColumnName = "id")
    @Comment("客户寄售库存内码")
    private InventoryConsign inventoryConsign;

    public List<InventoryConsign> makeInventoryConsigns() {
        List<InventoryConsign> inInventories = new ArrayList();
        if (getInventoryConsign() != null) {
            inInventories.add(getInventoryConsign());
        }
        return inInventories;
    }

    @Column(name = "product_qty", nullable = false, columnDefinition = ApesConst.FIELD_QTY_16_4_0)
    @Comment("数量")
    private double productQty = 0;

    public double getProductQty() {
        if (voucher == null) return productQty;
        if ((!voucher.isReturned() && productQty < 0) || (voucher.isReturned() && productQty > 0)) {
            throw new RuntimeException("凭证数量输入有误！");
        }
        return productQty;
    }

    @Transient
    public double sign() {
        return productQty / Math.abs(productQty);
    }

    @Column(name = "price_unit", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("含税单价")
    private double priceUnit = 0;

    @Column(name = "origin_price_unit", columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("原始含税单价")
    private double originPriceUnit = 0; //（销售倒扣时使用）

    @Column(name = "inner_sale_price_unit", columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("内部销售单价")
    private double innerSalePriceUnit = 0;

    public double getPriceUnit() {
        if (priceUnit < 0) throw new RuntimeException("凭证单价输入有误！");
        return priceUnit;
    }

    @Column(name = "price_subtotal", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("未含税金额")
    private double priceSubtotal = 0;

    @Column(name = "price_tax", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("税金")
    private double priceTax = 0;

    @Column(name = "price_total", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("总计")
    private double priceTotal = 0;

    @Column(name = "tax_cost_price", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("含税平均成本单价")
    private Double taxCostPrice;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "voucher_item_id", referencedColumnName = "id")
    @Comment("退货凭证明细行号（销售退货时使用）")
    private VoucherItem voucherItem;

    @Column(name = "discount", nullable = false, columnDefinition = ApesConst.FIELD_16_4_0)
    @Comment("折扣")
    private double discount = 0;

    @Column(name = "supply_chain_management_fee", nullable = false, columnDefinition = ApesConst.FIELD_16_4_0)
    @Comment("供应链管理费")
    private double supplyChainManagementFee = 0;

    @Column(name = "platform_management_fee", nullable = false, columnDefinition = ApesConst.FIELD_16_4_0)
    @Comment("平台管理费")
    private double platformManagementFee = 0;

    @Column(name = "supplier_ref", length = 30)
    @Comment("供应商参考")
    private String supplierRef;


    @Column(name = "loss_Quotation_fee", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("定损信息费合计")
    private double lossQuotationFee = 0;

    @Column(name = "platform_service_fee_reduced", nullable = false, columnDefinition = ApesConst.FIELD_16_4_0)
    @Comment("平台服务费减免额")
    private double platformServiceFeeReduced = 0;

    @Column(name = "platform_internal_reduced", nullable = false, columnDefinition = ApesConst.FIELD_16_4_0)
    @Comment("内部销售服务费减免额度")
    private double platformInternalReduced = 0;

    @Column(name = "base_platform_management_fee", columnDefinition = ApesConst.FIELD_16_4_0)
    @Comment("定损基地平台服务费")
    private double basePlatformManagementFee = 0;

    @Column(name = "sale_Commission", columnDefinition = ApesConst.FIELD_16_4_0)
    @Comment("分销佣金")
    private double saleCommission = 0;

    @Column(name = "fee_rate", columnDefinition = ApesConst.FIELD_16_4)
    @Comment("费率")
    private Double feeRate;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "original_Supplier_id", referencedColumnName = "id")
    @Comment("原始供应商")
    private PartyRole originalSupplier;

    public void computeAmt() {
        Map result = this.getTax().computeAll(this.getVoucher().getCompany(), priceUnit, productQty);
        priceTax = ((Double) result.get("taxAmt")).doubleValue();
        priceSubtotal = ((Double) result.get("totalExcluded")).doubleValue();
        priceTotal = ((Double) result.get("totalIncluded")).doubleValue();
    }

    /*
     * 功能：计算无税库存单价
     */
    public double computeExcludedPriceUnit() {
        double price = this.priceUnit;
        if (this.getTax() != null) {
            price = (double) this.getTax().computeAll(voucher.getCompany(), price, 1.0).get("totalExcluded");
        }
        return price;
    }

    public String computeOrigin() {
        return voucher.getOrigin() + "_" + originItemId;
    }

    /**
     * 用于指定商品价值库存
     */
    @Transient
    private List<InventoryBatch> inInventories;

    public List<InventoryBatch> makeInventoryBatches() {
        List<InventoryBatch> inInventories = new ArrayList();
        if (getInventoryBatch() != null) {
            inInventories.add(getInventoryBatch());
        } else if (getInInventories() != null) {
            inInventories.addAll(getInInventories());
        }
        return inInventories;
    }

    /**
     * 检查是否跨公司
     */
    @Transient
    public boolean cross() {
        return !voucher.getCompany().getId().equals(this.obtainOwner().getId());
    }


    public double computeBaseQty() {
        return computeQtyUnit(this.getProductQty());
    }

    /**
     * 计量单位换算（数量）
     */
    public double computeQtyUnit(double qty) {
        ProductUom baseUom = baseUom();
        if (this.getUom().getId() != baseUom.getId()) {
            return this.getUom().computeQty(qty, baseUom, true);
        }
        return qty;
    }

    public double computeBasePrice() {
        return computePriceUnit(this.getPriceUnit());
    }

    /**
     * 计量单位换算（金额）
     */
    public double computePriceUnit(double price) {
        ProductUom baseUom = baseUom();
        if (this.getUom().getId() != baseUom.getId()) {
            return this.getUom().computePrice(price, baseUom);
        }
        return price;
    }

    /**
     * 获取基本计量单位
     */
    public ProductUom baseUom() {
        return SpringManager.getBean(UomService.class).getUom(this.getVoucher().getCompany(), this.product);
    }

    public VoucherItem findVoucherItem(String businessId) {
        if (voucher.getVoucher() == null) {
            throw new RuntimeException("原凭证不允许为空！");
        }
        VoucherItem voucherItem = SpringManager.getBean(VoucherItemRepository.class).findOne(JpaDsl.toCriteriaByEq("voucher", voucher.getVoucher(), "originItemId", businessId)).orElse(null);
        if (voucherItem == null) {
            voucherItem = SpringManager.getBean(VoucherItemRepository.class).findOne(JpaDsl.toCriteriaByEq("voucher", voucher.getVoucher(), "sourceItemId", businessId)).orElse(null);
        }
        return voucherItem;
    }
}
